import { defineComponent, ref, computed, watchEffect, onMounted, onUnmounted, createVNode } from 'vue';
import { rotateWatermark, reRendering, getStyleStr, getPixelRatio } from './utils.js';

const BaseSize = 2;
const FontGap = 3;
const index = /* @__PURE__ */ defineComponent({
  name: 'Watermark',
  props: ['zIndex', 'rotate', 'width', 'height', 'image', 'content', 'font', 'gap', 'offset'],
  setup(props, {
    slots
  }) {
    const containerRef = ref(null);
    const watermarkRef = ref(null);
    const stopObservation = ref(false);
    const observer = ref(null);

    // 计算属性
    const gap = computed(() => props.gap ?? [100, 100]);
    const gapX = computed(() => gap.value[0] ?? 100);
    const gapY = computed(() => gap.value[1] ?? 100);
    const gapXCenter = computed(() => gapX.value / 2);
    const gapYCenter = computed(() => gapY.value / 2);
    const offsetLeft = computed(() => props.offset?.[0] ?? gapXCenter.value);
    const offsetTop = computed(() => props.offset?.[1] ?? gapYCenter.value);
    const fontSize = computed(() => props.font?.fontSize ?? 14);
    const fontWeight = computed(() => props.font?.fontWeight ?? 'normal');
    const fontStyle = computed(() => props.font?.fontStyle ?? 'normal');
    const fontFamily = computed(() => props.font?.fontFamily ?? 'sans-serif');
    const color = computed(() => props.font?.color ?? 'rgba(0,0,0,.26)');

    // 样式计算
    const markStyle = computed(() => {
      const style = {
        'z-index': props.zIndex ?? 9,
        position: 'absolute',
        left: '0px',
        top: '0px',
        width: '100%',
        height: '100%',
        'pointer-events': 'none',
        'background-repeat': 'repeat',
        'background-position': ''
      };
      let positionLeft = offsetLeft.value - gapXCenter.value;
      let positionTop = offsetTop.value - gapYCenter.value;
      if (positionLeft > 0) {
        style.left = `${positionLeft}px`;
        style.width = `calc(100% - ${positionLeft}px)`;
        positionLeft = 0;
      }
      if (positionTop > 0) {
        style.top = `${positionTop}px`;
        style.height = `calc(100% - ${positionTop}px)`;
        positionTop = 0;
      }
      style['background-position'] = `${positionLeft}px ${positionTop}px`;
      return style;
    });

    // 方法
    const destroyWatermark = () => {
      if (watermarkRef.value) {
        watermarkRef.value.remove();
        watermarkRef.value = null;
      }
    };
    const appendWatermark = (base64Url, markWidth) => {
      if (containerRef.value && watermarkRef.value) {
        stopObservation.value = true;
        watermarkRef.value.setAttribute('style', getStyleStr({
          ...markStyle.value,
          'background-image': `url('${base64Url}')`,
          'background-size': `${(gapX.value + markWidth) * BaseSize}px`
        }));
        containerRef.value.append(watermarkRef.value);
        setTimeout(() => {
          stopObservation.value = false;
        });
      }
    };
    const getMarkSize = ctx => {
      let defaultWidth = 120;
      let defaultHeight = 64;
      const content = props.content;
      const image = props.image;
      const width = props.width;
      const height = props.height;
      if (!image && ctx.measureText) {
        ctx.font = `${Number(fontSize.value)}px ${fontFamily.value}`;
        const contents = Array.isArray(content) ? content : [content];
        const widths = contents.map(item => ctx.measureText(item).width);
        defaultWidth = Math.ceil(Math.max(...widths));
        defaultHeight = Number(fontSize.value) * contents.length + (contents.length - 1) * FontGap;
      }
      return [width ?? defaultWidth, height ?? defaultHeight];
    };
    const fillTexts = (ctx, drawX, drawY, drawWidth, drawHeight) => {
      const ratio = getPixelRatio();
      const content = props.content;
      const mergedFontSize = Number(fontSize.value) * ratio;
      ctx.font = `${fontStyle.value} normal ${fontWeight.value} ${mergedFontSize}px/${drawHeight}px ${fontFamily.value}`;
      ctx.fillStyle = color.value;
      ctx.textAlign = 'center';
      ctx.textBaseline = 'top';
      ctx.translate(drawWidth / 2, 0);
      const contents = Array.isArray(content) ? content : [content];
      contents?.forEach((item, index) => {
        ctx.fillText(item ?? '', drawX, drawY + index * (mergedFontSize + FontGap * ratio));
      });
    };
    const renderWatermark = () => {
      const canvas = document.createElement('canvas');
      const ctx = canvas.getContext('2d');
      const image = props.image;
      const rotate = props.rotate ?? -22;
      if (ctx) {
        if (!watermarkRef.value) {
          watermarkRef.value = document.createElement('div');
        }
        const ratio = getPixelRatio();
        const [markWidth, markHeight] = getMarkSize(ctx);
        const canvasWidth = (gapX.value + markWidth) * ratio;
        const canvasHeight = (gapY.value + markHeight) * ratio;
        canvas.setAttribute('width', `${canvasWidth * BaseSize}px`);
        canvas.setAttribute('height', `${canvasHeight * BaseSize}px`);
        const drawX = gapX.value * ratio / 2;
        const drawY = gapY.value * ratio / 2;
        const drawWidth = markWidth * ratio;
        const drawHeight = markHeight * ratio;
        const rotateX = (drawWidth + gapX.value * ratio) / 2;
        const rotateY = (drawHeight + gapY.value * ratio) / 2;
        const alternateDrawX = drawX + canvasWidth;
        const alternateDrawY = drawY + canvasHeight;
        const alternateRotateX = rotateX + canvasWidth;
        const alternateRotateY = rotateY + canvasHeight;
        ctx.save();
        rotateWatermark(ctx, rotateX, rotateY, rotate);
        if (image) {
          const img = new Image();
          img.onload = () => {
            ctx.drawImage(img, drawX, drawY, drawWidth, drawHeight);
            ctx.restore();
            rotateWatermark(ctx, alternateRotateX, alternateRotateY, rotate);
            ctx.drawImage(img, alternateDrawX, alternateDrawY, drawWidth, drawHeight);
            appendWatermark(canvas.toDataURL(), markWidth);
          };
          img.crossOrigin = 'anonymous';
          img.referrerPolicy = 'no-referrer';
          img.src = image;
        } else {
          fillTexts(ctx, drawX, drawY, drawWidth, drawHeight);
          ctx.restore();
          rotateWatermark(ctx, alternateRotateX, alternateRotateY, rotate);
          fillTexts(ctx, alternateDrawX, alternateDrawY, drawWidth, drawHeight);
          appendWatermark(canvas.toDataURL(), markWidth);
        }
      }
    };
    const onMutate = mutations => {
      if (stopObservation.value) return;
      mutations.forEach(mutation => {
        if (watermarkRef.value && reRendering(mutation, watermarkRef.value)) {
          destroyWatermark();
          renderWatermark();
        }
      });
    };
    watchEffect(() => {
      renderWatermark();
    });

    // 生命周期
    onMounted(() => {
      observer.value = new MutationObserver(onMutate);
      if (containerRef.value) {
        observer.value.observe(containerRef.value, {
          attributes: true,
          subtree: true,
          childList: true,
          attributeFilter: ['style', 'class']
        });
      }
    });
    onUnmounted(() => {
      destroyWatermark();
      observer.value?.disconnect();
    });
    return () => createVNode("div", {
      "ref": containerRef,
      "class": "cm-watermark",
      "style": {
        position: 'relative'
      }
    }, [slots.default?.()]);
  }
});

export { index as default };
